Un Runtime Environment (entorno de ejecución) es basicamente un contenedor que contiene todo lo necesario para ejecutar código.
Esto es cierto para todos los lenguajes. Pero el Runtime Environment del que queremos hablar es del de Javascript y este se compone de las siguientes partes:
- APIs
- Engine
- Call Stack
- Memory Heap
- Callback/Tasks Queue
- Microtask Queue
- Event loop
Cada uno de estos elementos cumple una función específica y a continuación verás precisamente cual es la función de cadad uno
APIs
Son funcionalidades adicionales que se ponen a disposición del código del Javascript.
3 de los APIs mas utilizados en JS son:
- Web Storage
- Nos da acceso a funcionalidades para trabajar con localStorage o sessionStorage. Objetos utilizados para manejar memoria temporal de tu app web.
- DOM
- El mas famoso de los 3. Se utiliza para poder trabajar con la parte de la interfaz gráfica de una página.
- Web Workers
- Para manejar llamadas multithread con Javascript.
Por supuesto estos APIs están disponbiles solo cuando estamos utilizando JS en el navegador. No importa que navegador utilices, te proveerá acceso a sus APIs (también llamados Browser APIs o Web APIs).
¿Eso quiere decir que un navegador puede ser parte de un Runtime Environment?¡Pues no!
Esto quiere decir que el navegador ES el Runtime Environment.
Sin embargo por si no lo sabes JS también funciona para desarrollar apps y utilidades fuera de los navegadores. ¿Qué ocurre en esos casos?
Aquí entra el nombre de alguien famoso también. Seguramente habrás oído hablar de…NodeJS.
NodeJS es un Runtime Environment utilizado para ejecutar código Javascript en el back-end de un aplicación.
Cómo te podrás imaginar esto quiere decir que NodeJS provee sus propia funcionalidad a través de sus propios APIs.
- OS
- Utilizado para acceder a la información relacionada con el sistema operativo donde se está ejecutando el código.
- File System
- Permite crear, leer, modificar y borrar archivos, directorios y permisos.
¿Interesante no? Muchas de las funcionalidades que se utilizan día a día en Javascript no son realmente una característica íntrinseca del lenguaje sino es código proveído por el Runtime Environment.
Engine
Este es en esencia el corazón del Runtime Environment. Es el encargado de traducir el código de Javascript a código binario de manera que los sistemas puedan interpretarlo.
Todos los environments tienen su propio engine, tanto los navegadores como los que están hechos para ejecutar el back-end.
Runtime Environment | Tipo de Runtime Environment | Engine |
Chrome | Navegador | V8 |
Edge | Navegador | Chakra |
Firefox | Navegador | SpiderMonkey |
Safari | Navegador | JavascriptCore |
NodeJS | Back-end | V8 |
Deno | Back-end | V8 |
Como puedes ver nada impide que varios Runtime Environments utilicen el mismo Engine. En estos ejemplos V8 es el qué mas se repite. Si te vas a aprender solo 1 te recomendaría que recuerdes este, ya que es el mas popular en la actualidad.
¿Y en qué se diferencia un engine de otro?
Bueno para entender las diferencias debes primero entender que todos los engines se rigen por EcmaScript.
¿Qué? ¿Otro lenguaje de programación? No, el nombre es engañoso.
EcmaScript no es un lenguaje de programación, sino mas bien es un estándar o especificación de lenguajes. Como estandár es el que define el nombre y el comportamiento que se espera de ciertas funciones que como programador de JS ya esperamos que estén ahí.
Pero EcmaScript no sólo se limita a Javascript. También se utiliza como estándar para otros lenguajes como JScript y ActionScript.
Si te da curiosidad aprender un poquito más de EcmaScript y quién esta detrás del mismo, puedes visitar ecma International.
Ahora vamos a lo importante. ¿Sabes como funciona un engine?
Para no hacer el cuento largo todos los engines hacen que tu código pase por 3 fases: Parseo, Compilación y Ejecución.
La diferencia entre engines recae en la parte final de la compilación y la ejecución. Es aquí donde sala relucir el valor de cada engine, ya que cada uno agrega su propias utilidades. El objetivo es optimizar lo mas posible el proceso de manera que el código se ejecute de manera mas eficiente.
Durante estas fases se hace uso de la Call Stack (Pila de Llamadas) y Memory Heap (Memoria de Almacenamiento Libre). Ambos elementos son parte del engine y son muy importantes.
El tema del engine es un poco mas extenso asi que revisa: Aprende lo básico de un engine en Javascript.
Una vez termines ese post, puedes regresar y continuar con este.
Callback Queue y Microtask Queue
La callback queue o task queue (fila de tareas) y la microtask queue (fila de microtareas) son las filas encargadas de mantener el orden de ejecución de las funciones callback asociadas con código asíncrono.
Casi todas las funciones callback esperan su ejecución dentro de la callback queue. Sin embargo algunas funciones de callback específicas, como las que estan asociadas a Promises, esperan dentro de la microtask queue.
Otra cosa importante a tener en cuenta es que Javascript siempre le da prioridad a la microtask queue. Esto quiere decir que en cualquier situación en la que ambas filas tengan funciones pendientes por ejecutar, JS no le hara caso a la Callback Queue hasta que la Microtask Queue este vacía.
Las funciones de ambas filas se agregan a la Call Stack siguiendo el orden FIFO – First In First Out. Lo cual simplemente quiere decir que la primera función que entro a la fila sera la primera que sale y así consecutivamente.
Event Loop
El Event Loop (Loop de Eventos/Bucle de eventos) es el sistema encargado de administrar las operaciones asíncronas. Él es el encargado de correr el único hilo de ejecución que existe y actualizar las funciones pendientes por ejecutar.
Cuando la Call Stack del engine de JS esta vacía el Event Loop revisa la Microtask Queue y la Callback Queue buscando funciones pendientes. En caso de encontrar una la coloca en la Call Stack.
Y ya eso es todo. La verdad es que como ya sospecharás cada componente del Runtime Environment tiene bastantes más temas para profundizar en ellos. Sin embargo no te espantes con las bases que has aprendido aquí ya tienes un gran trecho recorrido del camino.
Si quieres ver un pequeño ejemplo del Runtime Environment en acción puedes leer este post.